﻿#ifndef  OBJECT_POOL
#define OBJECT_POOL

#include <unordered_set>
#include <unordered_map>
#include <mutex>
class Reflectable;

namespace ObjectPool
{
	typedef unsigned long long ObjectId;
	static const ObjectId InvalidId = 0;

	

	typedef std::mutex NormalLock;
	class NoLock {
	public:
		void lock() {

		}
		void unlock() {

		}
	};

	template<typename T,typename LockType = NoLock>
	class ObjectPoolBase {
	private:
		ObjectId AllocId() {
			auto id = MaxId;
			MaxId++;
			return id;
			
		}

		void DoRegister(T* obj) {
			auto id = AllocId();
			_ids[obj] = id;
			_objs[id] = obj;
		}

		T* DoTake() {
			if (!_ids.empty()) {
				auto ret = *rest.begin();
				_ids.erase(ret);
				return ret;
			}
			return NULL;
		}

		template<typename T2>
		typename std::enable_if<std::is_base_of<T, T2>::value || std::is_same<T,T2>::value, T2*>::type DoCreate() {
			auto ret = new T2();
			DoRegister(ret);
			return ret;
		}

	public:
		ObjectPoolBase():MaxId(1) {
		}
		~ObjectPoolBase() {
			for (auto i : _objs) {
				delete i.second;
			}
		};

		T* TakeOne() {
			std::lock_guard<LockType> locker(mutex);
			return DoTake();
		}

		T* TakeOrCreate() {
			std::lock_guard<LockType> locker(mutex);
			auto ret = DoTake();
			if (ret)
			{
				return ret;
			}
			return DoCreate<T>();
		}

		void PutBack(T* t) {
			std::lock_guard<LockType> locker(mutex);
			if (_ids.count(t)) {
				rest.insert(t);
			}
		}

		ObjectId Register(T* t) {
			std::lock_guard<LockType> locker(mutex);
			DoRegister(t);
		}

		template<typename T2>
		typename std::enable_if<std::is_base_of<T, T2>::value, T2*>::type Create() {
			std::lock_guard<LockType> locker(mutex);
			return DoCreate();
		}

		T* Create() {
			std::lock_guard<LockType> locker(mutex);
			ObjectId id = AllocId();
			T* ret = new T();
			return ret;
		};

		void Destory(T* obj)
		{
			std::lock_guard<LockType> locker(mutex);
			if (_ids.count(obj)) {
				rest.erase(obj);
				auto id = _ids[obj];
				_ids.erase(obj);
				_objs.erase(id);
			}

		}

		T* SearchObj(ObjectId id) {
			std::lock_guard<LockType> locker(mutex);
			if (_objs.count(id)) {
				return _objs[id];
			}
			return InvalidId;
		}

		ObjectId GetId(T* obj) {
			std::lock_guard<LockType> locker(mutex);
			if (_ids.count(obj)) {
				return _ids[obj];
			}

			return InvalidId;
		}

	private:

		std::unordered_set<T*> rest;
		std::unordered_map<T*, ObjectId> _ids;
		std::unordered_map<ObjectId,T*> _objs;
		LockType mutex;
		ObjectId MaxId;
	};

	typedef ObjectPoolBase<Reflectable> ReflectableObjectPool;
}




#endif // ! OBJECT_POOL
